package spring.cloud.tasks.tasks_manager.task_item_assign;


import com.google.common.cache.*;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * @author huihui
 */
@Slf4j
public class TaskItemContainer {
    /**
     * 执行器支持的任务列表。为什么不使用map而使用cache,主要考虑的就是如果执行器节点失效了，那对应的任务列表也就失效了。
     * 全局cache不会出现线程安全问题
     */
    public static LoadingCache<String, ExecutorSupportedTaskIdList> executorIdToExecutorSupportedTaskIdListCache = null;

    static {
        //缓存接口这里是LoadingCache，LoadingCache在缓存项不存在时可以自动加载缓存
        LoadingCache<String, ExecutorSupportedTaskIdList> cache
                //CacheBuilder的构造函数是私有的，只能通过其静态方法newBuilder()来获得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                //设置并发级别，并发级别是指可以同时写缓存的线程数
                .concurrencyLevel(1)
                //设置写缓存后N秒钟过期
                .expireAfterWrite(16, TimeUnit.MINUTES)//add by huihui: 基于主动刷新+异步失效机制
                //设置写缓存后N秒钟刷新(Guava Cache特性：对于同一个key，只让一个请求回源load数据，其他线程阻塞等待结果"提到：如果缓存过期，恰好有多个线程读取同一个key的值，那么guava只允许一个线程去加载数据，其余线程阻塞。这虽然可以防止大量请求穿透缓存，但是效率低下。使用refreshAfterWrite可以做到：只阻塞加载数据的线程，其余线程返回旧数据。)
                .refreshAfterWrite(1, TimeUnit.SECONDS)//add by huihui:只要在从ZK读取数据期间读取数据阻塞即可，在这(单线程操作)感觉没有任何意义。
                //设置缓存容器的初始容量为N
                .initialCapacity(1024)
                //设置缓存最大容量为N，超过N之后就会按照LRU最近虽少使用算法来移除缓存项
                .maximumSize(1024)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存的移除通知
                .removalListener(new RemovalListener<Object, Object>() {
                    @Override
                    public void onRemoval(RemovalNotification<Object, Object> removalNotification) {
                        log.debug(removalNotification.getKey() + " 被移除了，原因： " + removalNotification.getCause());
                    }
                })
                //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
                .build(
                        new CacheLoader<String, ExecutorSupportedTaskIdList>() {
                            @Override
                            public ExecutorSupportedTaskIdList load(String key) throws Exception {
                                log.debug("缓存没有时，从数据库加载" + key);
                                return ExecutorSupportedTaskIdList.$null$;
                            }
                        }
                );
        cache.cleanUp();
        TaskItemContainer.executorIdToExecutorSupportedTaskIdListCache = cache;
    }

    /**
     * 已经分配好的任务分片容器
     */
    public ExecutorTaskItemListContext assignedExecutorTaskItemListContext = new ExecutorTaskItemListContext();

}
